package br.uniceub.fsw.agenda.model.dao;

import br.uniceub.fsw.agenda.exception.BusinessException;
import br.uniceub.fsw.agenda.exception.ChildConstraintViolationException;
import br.uniceub.fsw.agenda.exception.DatabaseException;
import br.uniceub.fsw.agenda.exception.UniqueConstraintException;
import java.sql.Connection;
import java.util.List;
import br.uniceub.fsw.agenda.model.dao.TipoLogradouroDAO;
import br.uniceub.fsw.agenda.model.vo.LogradouroVO;
import br.uniceub.fsw.agenda.model.vo.TipoLogradouroVO;
import br.uniceub.fsw.agenda.model.vo.CidadeVO;
import br.uniceub.fsw.agenda.model.vo.BairroVO;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;

/**
 * 05/04/2008
 * @author Rodrigo Uchôa - rodrigo.uchoa@yahoo.com
 *
 */
public class LogradouroDAO extends GenericDAO {
    
    public LogradouroDAO(Connection con) {
        super(con);
    }
    
    /**
     * Retorna todos os logradouros cadastrados ordenados por UF e Cidade.
     * @return List com objetos Logradouro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<LogradouroVO> findAll() throws DatabaseException {
        //montar consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT TB_LOGRADOURO.* FROM TB_LOGRADOURO, TB_UF, TB_CIDADE ");
        query.append(" WHERE TB_LOGRADOURO.ID_CIDADE = TB_CIDADE.ID_CIDADE");
        query.append(" AND TB_CIDADE.SG_UF = TB_UF.SG_UF");
        query.append(" ORDER BY TB_UF.SG_UF, TB_CIDADE.NO_CIDADE");
        
        List<LogradouroVO> listaRegistros = new ArrayList<LogradouroVO>();
        
        try {
            Statement st = con.createStatement();
            ResultSet rs = st.executeQuery(query.toString());
            while (rs.next()) {
                LogradouroVO logradouro = new LogradouroVO();
                
                logradouro.setIdLogradouro(rs.getInt("ID_LOGRADOURO"));
                
                TipoLogradouroDAO tipoLogradouroDAO = new TipoLogradouroDAO(this.con);
                
                TipoLogradouroVO tipoLogradouro = tipoLogradouroDAO.findById(rs.getInt("ID_TIPOLOGRADOURO"));
                
                logradouro.setTipoLogradouro(tipoLogradouro);
                
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                CidadeVO cidade = cidadeDAO.findById(rs.getInt("ID_CIDADE"));
                
                logradouro.setCidade(cidade);
                
                BairroDAO bairroDAO = new BairroDAO(this.con);
                
                BairroVO bairro = bairroDAO.findById(rs.getInt("ID_BAIRRO"));
                
                logradouro.setBairro(bairro);
                
                logradouro.setNrCep(rs.getInt("NR_CEP"));
                logradouro.setDsLogradouro(rs.getString("DS_LOGRADOURO"));
                
                listaRegistros.add(logradouro);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOLogradouro.findAll()", ex);
        }        
    }
    
    /**
     * Retorna Logradouro por idLogradouro
     * @param idLogradouro id do logradouro
     * @return Logradouro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public LogradouroVO findById(Integer idLogradouro) throws DatabaseException {
        //montar consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_LOGRADOURO ");
        query.append("WHERE ID_LOGRADOURO = ?");
        
        LogradouroVO logradouro = new LogradouroVO();
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, idLogradouro.toString());
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                logradouro.setIdLogradouro(rs.getInt("ID_LOGRADOURO"));
                
                TipoLogradouroDAO tipoLogradouroDAO = new TipoLogradouroDAO(this.con);
                
                TipoLogradouroVO tipoLogradouro = tipoLogradouroDAO.findById(rs.getInt("ID_TIPOLOGRADOURO"));
                
                logradouro.setTipoLogradouro(tipoLogradouro);
                
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                CidadeVO cidade = cidadeDAO.findById(rs.getInt("ID_CIDADE"));
                
                logradouro.setCidade(cidade);
                
                BairroDAO bairroDAO = new BairroDAO(this.con);
                
                BairroVO bairro = bairroDAO.findById(rs.getInt("ID_BAIRRO"));
                
                logradouro.setBairro(bairro);
                
                logradouro.setNrCep(rs.getInt("NR_CEP"));
                logradouro.setDsLogradouro(rs.getString("DS_LOGRADOURO"));
            }
            st.close();
            rs.close();
            return logradouro;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOLogradouro.findById()", ex);
        }        
    }
    
    /**
     * Retorna Logradouro por nrCep
     * @param nrCep número do cep
     * @return Logradouro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public LogradouroVO findByCep(Integer nrCep) throws DatabaseException {
        //montar consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_LOGRADOURO ");
        query.append("WHERE NR_CEP = ?");
        
        LogradouroVO logradouro = new LogradouroVO();
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, nrCep.toString());
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                logradouro.setIdLogradouro(rs.getInt("ID_LOGRADOURO"));
                
                TipoLogradouroDAO tipoLogradouroDAO = new TipoLogradouroDAO(this.con);
                
                TipoLogradouroVO tipoLogradouro = tipoLogradouroDAO.findById(rs.getInt("ID_TIPOLOGRADOURO"));
                
                logradouro.setTipoLogradouro(tipoLogradouro);
                
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                CidadeVO cidade = cidadeDAO.findById(rs.getInt("ID_CIDADE"));
                
                logradouro.setCidade(cidade);
                
                BairroDAO bairroDAO = new BairroDAO(this.con);
                
                BairroVO bairro = bairroDAO.findById(rs.getInt("ID_BAIRRO"));
                
                logradouro.setBairro(bairro);
                
                logradouro.setNrCep(rs.getInt("NR_CEP"));
                logradouro.setDsLogradouro(rs.getString("DS_LOGRADOURO"));
            }
            st.close();
            rs.close();
            return logradouro;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOLogradouro.findByCep()", ex);
        }        
    }
    
    /**
     * Retorna Logradouro pela descrição
     * @param dsLogradouro descrição
     * @return Logradouro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<LogradouroVO> findByDsLogradouro(String dsLogradouro) throws DatabaseException {
        //montar consulta
        String filtro = "%" + dsLogradouro + "%";
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_LOGRADOURO ");
        query.append("WHERE DS_LOGRADOURO LIKE ?");
        
        LogradouroVO logradouro = new LogradouroVO();
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, filtro);
            ResultSet rs = st.executeQuery();
            List<LogradouroVO> lista = new ArrayList<LogradouroVO>();
            
            while (rs.next()) {
                logradouro.setIdLogradouro(rs.getInt("ID_LOGRADOURO"));
                
                TipoLogradouroDAO tipoLogradouroDAO = new TipoLogradouroDAO(this.con);
                
                TipoLogradouroVO tipoLogradouro = tipoLogradouroDAO.findById(rs.getInt("ID_TIPOLOGRADOURO"));
                
                logradouro.setTipoLogradouro(tipoLogradouro);
                
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                CidadeVO cidade = cidadeDAO.findById(rs.getInt("ID_CIDADE"));
                
                logradouro.setCidade(cidade);
                
                BairroDAO bairroDAO = new BairroDAO(this.con);
                
                BairroVO bairro = bairroDAO.findById(rs.getInt("ID_BAIRRO"));
                
                logradouro.setBairro(bairro);
                
                logradouro.setNrCep(rs.getInt("NR_CEP"));
                logradouro.setDsLogradouro(rs.getString("DS_LOGRADOURO"));
                
                lista.add(logradouro);
            }
            st.close();
            rs.close();
            return lista;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOLogradouro.findByCep()", ex);
        }        
    }
    
    /**
     * Faz o insert de um novo logradouro e devolve a o id recem gerado
     * @param logradouro logradouro que se deseja inserir
     * @return ID auto-increment gerado para esse registro
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public Integer insert(LogradouroVO logradouro) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO TB_LOGRADOURO(ID_TIPOLOGRADOURO, ID_CIDADE");
        query.append(", ID_BAIRRO, NR_CEP, DS_LOGRADOURO)");        
        query.append(" VALUES (?,?,?,?,?)");             
        
        //retornar id gerado
        Integer generatedId = null;
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setInt(1, logradouro.getTipoLogradouro().getIdTipoLogradouro());
            st.setInt(2, logradouro.getCidade().getIdCidade());
            //testar se bairro é null
            if (logradouro.getBairro() != null) {
                st.setInt(3, logradouro.getBairro().getIdBairro());
            } else {
                st.setNull(3, Types.INTEGER);
            }
            st.setInt(4, logradouro.getNrCep());
            st.setString(5, logradouro.getDsLogradouro());            
            
            st.executeUpdate();
            
            //pegar id gerado
            ResultSet rs = st.getGeneratedKeys();
            while (rs.next()) {
                generatedId = new Integer(rs.getString(1));                
            }                    
            
            return generatedId;            
        } catch (SQLException ex) {            
            ex.printStackTrace();
            if (ex.getErrorCode() == 1062) {
                throw new UniqueConstraintException(ex.getMessage(), ex);                
            }
            throw new DatabaseException("Erro no DAOLogradouro.insert()", ex);            
        }      
    }
    
    public void delete(Integer idLogradouro) throws BusinessException, DatabaseException {
        String query = "DELETE FROM TB_LOGRADOURO WHERE ID_LOGRADOURO = ?";
        
        try {
            PreparedStatement st = con.prepareStatement(query);
            st.setInt(1, idLogradouro);
            st.executeUpdate();
        } catch (SQLException ex) {            
            ex.printStackTrace();
            if (ex.getErrorCode() == 1451) {
                throw new ChildConstraintViolationException(ex.getMessage(), ex);                
            }
            throw new DatabaseException("Erro no DAOLogradouro.delete()", ex);
        }
    }
    
    /**
     * Atualiza um registro da tabela logradouro de acordo com o objeto
     * logradouro passado como parametro.
     * @param logradouro
     * @return Objeto logradouro recem alterado, com seus novos atributos.
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public LogradouroVO update(LogradouroVO logradouro) throws BusinessException, DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("UPDATE TB_LOGRADOURO SET");
        query.append(" ID_TIPOLOGRADOURO = ?,");
        query.append(" ID_CIDADE = ?,");
        query.append(" ID_BAIRRO = ?," );
        query.append(" NR_CEP = ?,");
        query.append(" DS_LOGRADOURO = ?");
        query.append(" WHERE ID_LOGRADOURO = ?");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setInt(1, logradouro.getTipoLogradouro().getIdTipoLogradouro());
            st.setInt(2, logradouro.getCidade().getIdCidade());
            //testar se o bairro é null
            if (logradouro.getBairro() != null) {
                st.setInt(3, logradouro.getBairro().getIdBairro());
            } else {
                st.setNull(3, Types.INTEGER);
            }
            st.setInt(4, logradouro.getNrCep());
            st.setString(5, logradouro.getDsLogradouro());
            st.setInt(6, logradouro.getIdLogradouro());
            
            st.executeUpdate();
            return logradouro;
        } catch (SQLException ex) {
            //TODO verificar codigos de erro
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOLogradouro.update()", ex);
        }
    }

}
